package com.longsichao.lscframe.net;

import android.net.Uri;
import android.support.annotation.NonNull;

import com.longsichao.lscframe.ctrl.CachePolicy;
import com.longsichao.lscframe.model.LSCModel;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

import okhttp3.MediaType;

/**
 * @author SONG GUANYULONGSICHAO (leo.song[at]outlook[dot]com)
 */
public class Api {

    private CachePolicy cachePolicy;
    private long cacheValidTime;
    private Class<? extends LSCModel> modelClass;
    private List<FileSet> postFiles = null;
    private StringSet postString = null;
    private NetworkHelper.RequestMethod requestMethod;
    private String url;
    private RequestHeader header;

    private Api() {
    }

    public CachePolicy getCachePolicy() {
        return cachePolicy;
    }

    public long getCacheValidTime() {
        return cacheValidTime;
    }

    public Class<? extends LSCModel> getModelClass() {
        return modelClass;
    }

    public List<FileSet> getPostFiles() {
        return postFiles;
    }

    public StringSet getPostString() {
        return postString;
    }

    public NetworkHelper.RequestMethod getRequestMethod() {
        return requestMethod;
    }

    public String getUrl() {
        return url;
    }

    public RequestHeader getHeader() {
        return header;
    }

    public static class Builder {
        private CachePolicy cachePolicy = CachePolicy.NETWORK_ONLY;
        private long cacheValidTime = 0;
        private Class<? extends LSCModel> modelClass;
        private List<FileSet> postFiles = null;
        private StringSet postString = null;
        private List<StringSet> queryParameters = null;
        private NetworkHelper.RequestMethod requestMethod = NetworkHelper.RequestMethod.GET;
        private String baseUrl;
        private RequestHeader header = null;

        public Builder setCachePolicy(CachePolicy cachePolicy) {
            this.cachePolicy = cachePolicy;
            return this;
        }

        public Builder setCacheValidTime(long cacheValidTime) {
            this.cacheValidTime = cacheValidTime;
            return this;
        }

        public Builder setModelClass(Class<? extends LSCModel> modelClass) {
            this.modelClass = modelClass;
            return this;
        }

        public Builder addPostFile(FileSet postFile) {
            this.requestMethod = NetworkHelper.RequestMethod.POST;
            if (this.postFiles == null) {
                this.postFiles = new LinkedList<>();
            }
            for (FileSet fileSet : this.postFiles) {
                if (fileSet.name.equals(postFile.name)) {
                    fileSet.file = postFile.file;
                    return this;
                }
            }
            this.postFiles.add(postFile);
            return this;
        }

        public Builder setPostString(StringSet postString) {
            this.requestMethod = NetworkHelper.RequestMethod.POST;
            this.postString = postString;
            return this;
        }

        public Builder addQueryParameter(StringSet queryParameter) {
            if (this.queryParameters == null) {
                this.queryParameters = new LinkedList<>();
            }
            for (StringSet stringSet : this.queryParameters) {
                if (stringSet.name.equals(queryParameter.name)) {
                    stringSet.value = queryParameter.value;
                    return this;
                }
            }
            this.queryParameters.add(queryParameter);
            return this;
        }

        public Builder setBaseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
            return this;
        }

        public Api build() {
            Api api = new Api();
            api.cachePolicy = this.cachePolicy;
            api.cacheValidTime = this.cacheValidTime;
            api.modelClass = this.modelClass;
            api.requestMethod = this.requestMethod;
            api.postString = this.postString;
            api.header = this.header;

            if (api.postFiles == null) {
                api.postFiles = new LinkedList<>();
            }
            if (this.postFiles != null) {
                api.postFiles.clear();
                api.postFiles.addAll(this.postFiles);
            }

            if (queryParameters != null) {
                Uri.Builder builder = Uri.parse(baseUrl).buildUpon();
                for (StringSet stringSet : queryParameters) {
                    builder.appendQueryParameter(stringSet.name, stringSet.value);
                }
                api.url = builder.build().toString();
            } else {
                api.url = baseUrl;
            }

            return api;
        }

        public Builder setHeader(RequestHeader header) {
            this.header = header;
            return this;
        }
    }

    public static class StringSet {
        private String name;
        private String value;
        private MediaType mediaType;

        public StringSet(@NonNull String name, String value) {
            this.name = name;
            this.value = value == null ? "" : value;
        }

        public StringSet(@NonNull String name, int value) {
            this.name = name;
            this.value = value + "";
        }

        public StringSet(@NonNull String value, @NonNull MediaType mediaType) {
            this.value = value;
            this.mediaType = mediaType;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }

        public MediaType getMediaType() {
            return mediaType;
        }
    }

    public static class RequestHeader {
        private String name;
        private String value;
        private onResponseHeaderListener listener;

        public RequestHeader(@NonNull String name, @NonNull String value) {
            this(name, value, null);
        }

        public RequestHeader(@NonNull String name, @NonNull String value, onResponseHeaderListener listener) {
            this.name = name;
            this.value = value;
            this.listener = listener;
        }

        public onResponseHeaderListener getListener() {
            return listener;
        }

        public String getName() {
            return name;
        }

        public String getValue() {
            return value;
        }

        public interface onResponseHeaderListener {
            void onResponseHeader(String name, String value);
        }
    }

    public static class FileSet {
        private String name;
        private File file;
        private MediaType mediaType;

        public FileSet(@NonNull String name, @NonNull File file, @NonNull MediaType mediaType) {
            if (name.trim().isEmpty()) {
                throw new NullPointerException("Create a new FileSet by empty name.");
            }
            this.name = name;
            this.file = file;
            this.mediaType = mediaType;
        }

        public String getName() {
            return name;
        }

        public File getFile() {
            return file;
        }

        public MediaType getMediaType() {
            return mediaType;
        }
    }
}